package com.example.chinesenation.ElasticSearch.Impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.chinesenation.ElasticSearch.ElasticSearchService;
import com.example.chinesenation.Entity.Article;
import com.example.chinesenation.Entity.Policy;
import com.example.chinesenation.Exception.AuthenException;
import com.example.chinesenation.Redis.RedisService;
import com.example.chinesenation.Response.ResultType;
import com.example.chinesenation.Utils.CommonURL;
import com.example.chinesenation.Utils.DataChanges;
import com.example.chinesenation.VO.Search.VOArticleSearch;
import com.example.chinesenation.VO.Search.VOPolicySearch;
import com.example.chinesenation.VO.VOPolicy;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.fetch.subphase.highlight.Highlighter;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author sakuraFallingDown
 * @version 1.0
 * @date 2021/1/29 15:14
 */
@Configuration
public class ElasticSearcherImpl implements ElasticSearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private RedisService redisService;


    private final static String defaultNationName="暂未确定";

    private final static String defaultCategoryName="暂未确定";

    private final static int time=10;



    @Override
    public IPage<VOPolicySearch> searchPolicy(String nation,
                                              String keyword,
                                              Date start,
                                              Date end,
                                              int orderByType,
                                              int current,
                                              int size) throws IOException {

        SearchRequest searchRequest=new SearchRequest(CommonURL.policyIndex);//索引名
        SearchSourceBuilder builder=new SearchSourceBuilder();//创建buidler

        //匹配在标题和内容keyword关键字
        MatchQueryBuilder title = QueryBuilders.matchQuery("title", keyword);
        MatchQueryBuilder content = QueryBuilders.matchQuery("content", keyword);
        BoolQueryBuilder keywordQuery = new BoolQueryBuilder()
                .should(title);//暂时只考虑标题

        //是否有publishtime的排序
        RangeQueryBuilder rangeQuery=QueryBuilders.rangeQuery("publishTime");
        if(start!=null){
            rangeQuery=rangeQuery.gte(start.getTime());
        }
        if(end!=null) {
            rangeQuery = rangeQuery.lte(end.getTime());
        }

        //是否筛选民族
        BoolQueryBuilder nationQuery=new BoolQueryBuilder();
        if(nation!=null&&!nation.equals("")){
            MatchPhraseQueryBuilder nationName = QueryBuilders.matchPhraseQuery("nationName", nation);
            //TermQueryBuilder nationName1 = QueryBuilders.termQuery("nationName", defaultNationName);
            nationQuery=nationQuery.must(nationName);
        }

        //总的条件
        BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder()
                .must(keywordQuery)//关键词
                .must(rangeQuery)//时间筛选
                .must(nationQuery);//民族筛选


        //设置builder
        builder.query(boolQueryBuilder);

        //排序方式
        switch (orderByType){
            case 1:{
                builder.sort("publishTime", SortOrder.DESC);//最新发布
                break;
            }
            case 2:{
                builder.sort("pageview", SortOrder.DESC);//最多点击
                break;
            }
            default:{
                break;
            }
        }

        builder.from((current-1)*size);
        builder.size(size);
        builder.timeout(new TimeValue(time, TimeUnit.SECONDS));//设置请求时间

        //设置关键字高亮
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.requireFieldMatch(false);//只设置第一个为高亮

        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");

        builder.highlighter(highlightBuilder);
        searchRequest.source(builder);


        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        IPage<VOPolicySearch> iPage=new Page<>(current,size);
        List<VOPolicySearch> policySearches=new ArrayList<>();
        for(SearchHit searchHit:searchResponse.getHits().getHits()){
            //System.out.println(searchHit.getSourceAsMap());
            Policy policy=JSON.parseObject(JSON.toJSONString(searchHit.getSourceAsMap()), Policy.class);
            VOPolicySearch voPolicySearch=new VOPolicySearch();
            DataChanges.fromPolicyToVOPolicySearch(policy,voPolicySearch);
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            HighlightField titleHighLight=highlightFields.get("title");
            if(titleHighLight!=null){
                Text[] fragments = titleHighLight.fragments();
                StringBuilder newTitle= new StringBuilder();
                for (Text test:fragments) {
                    newTitle.append(test);
                }
                if(!newTitle.toString().equals("")){
                    voPolicySearch.setTitle(newTitle.toString());
                }
            }
            int pageView = redisService.getPageView(CommonURL.RedisPolicyPageView + policy.getId());
            voPolicySearch.setPageview(voPolicySearch.getPageview()+pageView);
            policySearches.add(voPolicySearch);
            //System.out.println(searchHit);
        }
        iPage.setRecords(policySearches);

        //填充总数与页面数
        iPage.setTotal(searchResponse.getHits().getTotalHits().value);
        long pages=searchResponse.getHits().getTotalHits().value/size;
        if(searchResponse.getHits().getTotalHits().value%size!=0){
            pages+=1;
        }
        iPage.setPages(pages);
        return iPage;
    }

    @Override
    public IPage<VOArticleSearch> searchArticle(String nation
            , String category
            , String keyword
            , Date start
            , Date end
            , int orderByType
            , int current
            , int size) throws IOException {
        SearchRequest searchRequest=new SearchRequest(CommonURL.articleIndex);//索引名
        SearchSourceBuilder builder=new SearchSourceBuilder();//创建buidler

        //匹配在标题和内容keyword关键字
        MatchQueryBuilder title = QueryBuilders.matchQuery("title", keyword);
        MatchQueryBuilder content = QueryBuilders.matchQuery("content", keyword);
        BoolQueryBuilder keywordQuery = new BoolQueryBuilder()
                .should(title);//暂时只考虑标题

        //是否有publishtime的排序
        RangeQueryBuilder rangeQuery=QueryBuilders.rangeQuery("publishDate");
        if(start!=null){
            rangeQuery=rangeQuery.gte(start.getTime());
        }
        if(end!=null) {
            rangeQuery = rangeQuery.lte(end.getTime());
        }

        //是否筛选民族
        BoolQueryBuilder nationQuery=new BoolQueryBuilder();
        if(nation!=null&&!nation.equals("")){
            MatchPhraseQueryBuilder nationName = QueryBuilders.matchPhraseQuery("nationName", nation);
            //TermQueryBuilder nationName1 = QueryBuilders.termQuery("nationName", defaultNationName);
            nationQuery=nationQuery.must(nationName);
        }
        //是否筛选种类
        BoolQueryBuilder categoryQuery=new BoolQueryBuilder();
        if(category!=null&&!category.equals("")){
            MatchPhraseQueryBuilder categoryName = QueryBuilders.matchPhraseQuery("categoryName", category);
            //TermQueryBuilder categoryName1 = QueryBuilders.termQuery("categoryName", defaultCategoryName);
            categoryQuery=categoryQuery.must(categoryName);
        }


        BoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder()
                .must(keywordQuery)
                .must(rangeQuery)
                .must(nationQuery)
                .must(categoryQuery);


        //设置builder
        builder.query(boolQueryBuilder);

        //排序方式
        switch (orderByType){
            case 1:{
                builder.sort("publishDate", SortOrder.DESC);//最新发布
                break;
            }
            case 2:{
                builder.sort("pageview", SortOrder.DESC);//最多点击
                break;
            }
            default:{
                break;
            }
        }

        builder.from((current-1)*size);
        builder.size(size);
        builder.timeout(new TimeValue(time, TimeUnit.SECONDS));//设置请求时间


        //设置关键字高亮
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.requireFieldMatch(false);//只设置第一个为高亮
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");



        builder.highlighter(highlightBuilder);
        searchRequest.source(builder);


        SearchResponse searchResponse =restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        IPage<VOArticleSearch> iPage=new Page<>(current,size);
        List<VOArticleSearch> articleSearches=new ArrayList<>();
        for(SearchHit searchHit:searchResponse.getHits().getHits()){
            //System.out.println(searchHit.getSourceAsMap());
            Article article=JSON.parseObject(JSON.toJSONString(searchHit.getSourceAsMap()), Article.class);
            VOArticleSearch voArticleSearch=new VOArticleSearch();
            DataChanges.fromArticleToVOArticleSearch(article,voArticleSearch);
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            HighlightField titleHighLight=highlightFields.get("title");
            if(titleHighLight!=null){
                Text[] fragments = titleHighLight.fragments();
                StringBuilder newTitle= new StringBuilder();
                for (Text test:fragments) {
                    newTitle.append(test);
                }
                if(!newTitle.toString().equals("")){
                    voArticleSearch.setTitle(newTitle.toString());
                }
            }
            int pageView = redisService.getPageView(CommonURL.RedisArticlePageView + article.getId());
            voArticleSearch.setPageview(voArticleSearch.getPageview()+pageView);
            articleSearches.add(voArticleSearch);
            //System.out.println(searchHit);
        }
        iPage.setRecords(articleSearches);

        //填充总数与页面数
        iPage.setTotal(searchResponse.getHits().getTotalHits().value);
        long pages=searchResponse.getHits().getTotalHits().value/size;
        if(searchResponse.getHits().getTotalHits().value%size!=0){
            pages+=1;
        }
        iPage.setPages(pages);
        return iPage;
    }

    @Override
    public void updateArticlePageView(HashMap<String, Integer> articlePageView) {
        BulkRequest bulkRequest=new BulkRequest();
        for(Map.Entry<String,Integer> entry:articlePageView.entrySet()){
            UpdateRequest updateRequest=new UpdateRequest(CommonURL.articleIndex, entry.getKey());
            Article article=new Article();
            article.setPageview(entry.getValue());
            updateRequest.doc(JSON.toJSONString(article), XContentType.JSON);
            bulkRequest.add(updateRequest);
        }
        try {
            restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new AuthenException(ResultType.ElasticSearchUpdatePageViewError);
        }
    }

    @Override
    public void updatePolicyPageView(HashMap<String, Integer> policyPageView) {
        BulkRequest bulkRequest=new BulkRequest();
        for(Map.Entry<String,Integer> entry:policyPageView.entrySet()){
            UpdateRequest updateRequest=new UpdateRequest(CommonURL.policyIndex, entry.getKey());
            Policy policy=new Policy();
            policy.setPageview(entry.getValue());
            updateRequest.doc(JSON.toJSONString(policy), XContentType.JSON);
            bulkRequest.add(updateRequest);
        }
        try {
            restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new AuthenException(ResultType.ElasticSearchUpdatePageViewError);
        }
    }
}
